#include "javawriter.h"

JavaWriter::JavaWriter()
{
}

void JavaWriter::run()
{
    // save dir
    QDir dir(this->_filePath);

    // creating project dir
    if (!dir.mkdir(this->_project->name()) && !dir.exists()) {
        return;
    }

    // changing into new dir
    dir.cd(this->_project->name());

    // writing items
    this->writeDir(this->_project->umlItemRoot(), &dir);

}

void JavaWriter::writeDir(UmlDirItem *dir, QDir *filePath)
{
    QString path = filePath->path();

    BlueJProject bluejProject;

    bluejProject.setPath(path);

    BlueJProperty package("package");
    package.appendAttribute("showExtends", "true");
    package.appendAttribute("showUses", "true");

    bluejProject.appendProperty(package);

    int count = 1;

    foreach(UmlGraphicsItem *item, dir->items()) {

        // creating sub dir
        if (item->isOfType(UmlItem::UmlPackageItemType)) {
            UmlDirItem *dir = static_cast<UmlDirItem*>(item);

            filePath->mkdir(dir->name());
            filePath->cd(dir->name());

            this->writeDir(dir, filePath);
        }

        // writing class
        if (item->isOfType(UmlItem::UmlClassItemType)) {
            UmlClassItem *classItem = static_cast<UmlClassItem*>(item);

            this->writeClass(classItem, path);

            BlueJProperty target(QString("target%1").arg(count));
            target.appendAttribute("name", classItem->name());
            target.appendAttribute("type", "ClassTarget");
            target.appendAttribute("x", QVariant(classItem->pos().x()).toString());
            target.appendAttribute("y", QVariant(classItem->pos().y()).toString());

            bluejProject.appendProperty(target);

            count++;
        }

    }

    bluejProject.write();
}

void JavaWriter::writeClass(UmlClassItem *classItem, QString &path)
{
    // setting filename
    QString fileName = QString("%1.java").arg(classItem->name());

    // creating file
    QFile file(path + "/" + fileName);
    QByteArray content = "";

    // abstract keyword
    if (classItem->isAbstract()) {
        content += "public abstract ";
    }

    else if (classItem->isInterface()) {
        content += "interface ";
    }

    else {
        content += "public class ";
    }

    content += classItem->name();

    // generalizations
    if (!classItem->parentClasses().isEmpty()) {

        content += " extends ";

        QStringList parents;
        foreach (UmlRelation *relation, classItem->parentClasses()) {
            parents.append(relation->item2()->name());
        }

        content += parents.join(", ");
    }

    // realizations
    if (!classItem->realizedInterfaces().isEmpty()) {

        content += " implements ";

        QStringList parents;
        foreach (UmlRelation *relation, classItem->realizedInterfaces()) {
            parents.append(relation->item2()->name());
        }

        content += parents.join(", ");
    }

    content += " {\n\n";

    this->writeClassAttributes(classItem, &content);
    this->writeAssociations(classItem, &content);
    this->writeClassMethod(classItem, &content);

    content +=  "}";

    file.open(QIODevice::WriteOnly);
    file.write(content);
    file.close();
}

void JavaWriter::writeClassAttributes(UmlClassItem *classItem, QByteArray *content)
{
    if (!classItem->hasAttributes()) {
        return;
    }

    foreach(ClassAttribute *att, classItem->attList()) {
        JavaBlockComment comment(1);
        comment.appendLine(tr("class attribute: ") + att->name());

        content->append(comment.text());
        content->append("\t" + att->visibilityToString() + " " + att->returnType() + " " + att->name() + ";\n\n");
    }
}

void JavaWriter::writeClassMethod(UmlClassItem *classItem, QByteArray *content)
{
    if (!classItem->hasMethods()) {
        return;
    }

    foreach (ClassMethod *meth, classItem->methList()) {
        JavaBlockComment comment(1);
        comment.appendLine(tr("class method: ") + meth->name());

        content->append(comment.text());
        content->append("\t" + meth->visibilityToString() + " " + meth->returnType() + " " + meth->name() + "(");

        if (meth->hasArguments()) {
            QListIterator<ClassAttribute*> iter(meth->argList());
            while (iter.hasNext()) {
                ClassAttribute *att = iter.next();
                content->append(att->returnType() + " " + att->name());
                if (iter.hasNext()) {
                    content->append(", ");
                }
            }
        }

        content->append(") {\n");
        content->append("\t\t // Implementierung\n");
        content->append("\t}\n\n");
    }
}

void JavaWriter::writeAssociations(UmlClassItem *classItem, QByteArray *content)
{
    int count = 0;
    foreach (UmlRelation *relation, classItem->relations(UmlRelation::UmlAssociationRelationType)) {
        UmlRelationalItem *item = 0;
        UmlCardinality c;
        QString role = "";
        QString label = relation->name();

        if (relation->item1() == classItem) {
            item = relation->item2();
            c = relation->cardinalityItem2();
            role = relation->roleItem2();
        } else {
            item = relation->item1();
            c = relation->cardinalityItem1();
            role = relation->roleItem1();
        }

        JavaBlockComment comment(1);
        comment.appendLine(tr("Association: ") + label);

        if (!role.isEmpty()) {
            comment.appendLine(tr("Role: ") + role);
        }

        if (!c.isNull()) {
            comment.appendLine(tr("Cardinality: ") + c.lowerBound() + "..." + c.upperBound());
        }

        content->append(comment.text());

        if (c == UmlCardinality("1", "*") || c == UmlCardinality("*", "*")) {
            content->append(QString("\t LinkedList<%1> %2;").arg(item->name()).arg("association_" + QString(count)));
        }

        else {
            content->append(QString("\t%1 association_%2;").arg(item->name()).arg(count));
        }
        count++;
    }

    content->append("\n");
}
